package openIDService;

import java.io.IOException;
import java.util.List;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import models.User;

import org.openid4java.consumer.ConsumerException;
import org.openid4java.consumer.ConsumerManager;
import org.openid4java.discovery.DiscoveryException;
import org.openid4java.discovery.DiscoveryInformation;
import org.openid4java.message.AuthRequest;
import org.openid4java.message.MessageException;
import org.openid4java.message.ax.FetchRequest;
import org.openid4java.message.sreg.SRegRequest;

import utilities.GestoreLink;

/**
 * Il processo di Autenticazione nel forum.
 * 
 */
public class Authentication implements OpenIDService {

	private HttpServletResponse response;

	/**
	 * 
	 * @param response
	 *            {@link HttpServletResponse} oggetto che sara' indirizzato al client.
	 *            E' necessario per effettuare il reindirizzamento.
	 */
	public Authentication(HttpServletResponse response) {
		this.response = response;
	}

	private static ConsumerManager manager = new ConsumerManager();

	/**
	 * Prende una istanza di (@link {@link ConsumerManager} la quale e' coinvolta nel processo di autenticazione
	 * N.B: DEVE essere la stessa istanza per tutto il processo di autenticazione (e di verifica).
	 * 
	 * @return {@link ConsumerManager} object
	 */
	public static ConsumerManager getManager() {
		return manager;
	}

	/**
	 * Esegue il processo di autenticazione. Reindirizza inoltre il client alla pagina di login
	 * del provider OpenID (ad esempio Google, Verisign, etc...) usando la {@link HttpServletResponse }
	 * passata al costruttore.
	 * 
	 * @return {@link User} object, sempre nullo
	 * @param request
	 *            L'oggetto {@link HttpServletRequest} contenente la richiesta del client.
	 *            E' necessario salvare un semi-risultato dell'autenticazione nella sessione.
	 *            
	 *@param userID
	 *            String object contenente l'url OpenID associato all'utente.
	 *           
	 */
	@Override
	public User execute(HttpServletRequest request, String userID)
			throws DiscoveryException, MessageException, ConsumerException {

		List<?> discoveries = manager.discover(userID);

		DiscoveryInformation discovered = manager.associate(discoveries);

		request.getSession().setAttribute("discoveredInformation", discovered);

		AuthRequest authReq = createOpenIdAuthRequest(discovered);

		System.out.println(authReq.getDestinationUrl(true));
		try {
			response.sendRedirect(authReq.getDestinationUrl(true));

		} catch (IOException e) {
			e.printStackTrace();
		}

		return null;
	}

	private static AuthRequest createOpenIdAuthRequest(
			DiscoveryInformation discoveryInformation) {
		AuthRequest aut = null;

		try {
			aut = getManager().authenticate(discoveryInformation,
					GestoreLink.getGestore().getElement("Forum"));

			FetchRequest fetch = FetchRequest.createFetchRequest();

			fetch.addAttribute("FirstName", GestoreLink.getGestore()
					.getElement("FirstName"), true);
			fetch.addAttribute("LastName",
					GestoreLink.getGestore().getElement("LastName"), true);
			fetch.addAttribute("Email",
					GestoreLink.getGestore().getElement("Email"), true);

			SRegRequest sRegRequest = SRegRequest.createFetchRequest();

			sRegRequest.addAttribute("email", false);
			sRegRequest.addAttribute("fullname", false);

			aut.addExtension(sRegRequest);
			aut.addExtension(fetch);

		} catch (Exception e) {
			String message = "Exception occurred while building "
					+ "AuthRequest object!";
			System.err.println(message);
			throw new RuntimeException(message, e);
		}
		return aut;
	}
}